<?php
	require_once CODER_PATH.'/Conf/config.php';	
	require_once APPLICATION_PATH.'/Conf/config.php';

	class BaseModel {
		protected static $db;	
		protected $name = "";
		protected $primary = "id";
		
		public $error;
		
		public $autoValidateRule = array();			// 自动校验规则
		public $data = array();						// 数据信息
		protected $fields = array();				// 字段信息
		protected $autoCheckFields   =   true;		// 是否自动检测数据表字段信息
	
		const VALIDATE_IN = "in";					// 校验在"val1, val2, ..."  or array(value1, value2, ...)等字段内
		const VALIDATE_NOTIN = "notin";				// 校验不在字段内
		const VALIDATE_REQUIRE = "require";			// 校验有此字段
		const VALIDATE_BEWTEEN = "bewteen";			// 校验在 "min, max" 范围内
		const VALIDATE_NOTBEWTEEN = "notbewteen";	// 校验不在范围内
		const VALIDATE_LENGTH = "length";			// 校验长度在 "min, max" 范围内
		const VALIDATE_EXPIRE = "expire";			// 校验有"rule"字段
		const VALIDATE_REGEX = "regex";				// 校验"rule"正则表达式
		const VALIDATE_FUNCTION = "function";		// 自定义函数校验
		const VALIDATE_UNIQUE = "unique";			// 校验是否在数据库唯一
		const VALIDATE_CONFRIM = "confirm";			// 校验是否与"rule"字段相等
		const VALIDATE_EQUAL = "equal";				// 校验是否等于"rule"
		const VALIDATE_NOTEQUAL = "notequal";		// 校验是否不等于"rule"
		
		public function __construct() {
			self::$db = self::getInstance();
		}
		
		public function _destruct() {
			
		}
		
		// 实现单例
		public static function getInstance() {
			if (is_null(self::$db)) {
				self::$db = DbDriver::factory(DB_TYPE, DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PCONNET);
				if(self::$db == null) {
					_error("don't support ".DB_TYPE." Database", 'fatal');
				}
				self::$db->debug = DEBUG_DB;
			}
			return self::$db;
		}
		
		public function setNames($charset) {
			self::$db->query("SET NAMES ".$charset);
		}
		
		/**
		 * function: 查询单行数据
		 * @param string $where 筛选where语句
		 * @return array 单行数据
		 */
		public function fetch($where = null, array $fields = null) {
			$sql = "SELECT ".$this->parseField($fields)." FROM $this->name".$this->parseWhere($where)." LIMIT 0,1";
			$res = self::$db->query($sql);
			return self::$db->fetch_array($res); 
		}
		
		/**
		 * function: 查询单行数据
		 * @param string $where 筛选where语句
		 * @return array 单行数据 (与fetch的区别在于无数字key)
		 */
		public function assoc($where = null, array $fields = null) {
			$sql = "SELECT ".$this->parseField($fields)." FROM $this->name".$this->parseWhere($where)." LIMIT 0,1";
			$res = self::$db->query($sql);
			return self::$db->assoc_array($res);
		}
		
		/**
		 * 查询多行数据
		 * @param string $where WHERE语句
		 * @param string $order ORDER语句
		 * @param string $count 记录的数量
		 * @param string $offset 偏移量
		 * @return multitype:unknown 多行记录
		 */
		public function fetchAll($where = null, $fields = null, $order = null, $count = null, $offset = null) {
			$sql = "SELECT ".$this->parseField($fields)." FROM $this->name".$this->parseWhere($where);
			
			if($order != null) 	$sql .= " $order";
	
			if($offset != null) $option .= " $offset, ";
			
			if($count != null)  $option .= " $count";
				
			if( isset($option))	$sql .= " LIMIT ".$option;
	
			return self::$db->fetchAll($sql);
		}
		
		/**
		 * 查询多行数据
		 * @param string $where WHERE语句
		 * @param string $order ORDER语句
		 * @param string $count 记录的数量
		 * @param string $offset 偏移量
		 * @return multitype:unknown 多行记录(区别fetchAll无数字key)
		 */
		public function assocAll($where = null, array $fields = null, $order = null, $count = null, $offset = null) {
			$sql = "SELECT ".$this->parseField($fields)." FROM $this->name".$this->parseWhere($where);
			
			if($order != null) 	$sql .= " $order";
	
			if($offset != null) $option .= " $offset, ";
			
			if($count != null)  $option .= " $count";
				
			if( isset($option))	$sql .= " LIMIT ".$option;
			
			return self::$db->assocAll($sql);
		}
		
		/**
		 * 返回单行记录
		 * @param unknown $id 主键ID
		 * @return multitype: 单行记录
		 */
		public function find($id, $fields = null) {
			$sql = "SELECT ".$this->parseField($fields)." FROM $this->name WHERE $this->primary = $id LIMIT 0,1";
			$res = self::$db->query($sql);
			return self::$db->assoc_array($res); 
		}
		
		/**
		 * 删除单行记录
		 * @param string $where WHERE语句
		 * @return 为真执行成功
		 */
		public function delete($where = null) {
			$sql = "DELETE FROM $this->name" . $this->parseWhere($where);
			return self::$db->query($sql);
		}
		
		/**
		 * 更新单条记录
		 * @param array $data 记录ARRAY(KEY=>VALUE)
		 * @param unknown $where
		 * @return resource 为真表示执行成功
		 */
		public function update($where, array $data = null) {
			$data = $this->activeRecordCall($data);
			$sql = "UPDATE $this->name SET ".$this->parseUpdateOption($data)." WHERE $where";
			 return self::$db->query($sql);
		}
		
		/**
		 * 插入单条记录
		 * @param array $data ARRAY(KEY=>VALUE)
		 * @return number 为真执行成功
		 */
		public function insert(array $data = null) {
			$data = $this->activeRecordCall($data);
			
			$keyValueStr = $this->parseKeyValue($data);
			$sql = "INSERT INTO $this->name(".$keyValueStr["key"].") VALUES(".
					$keyValueStr["value"].")";
			
			self::$db->query($sql);
			return self::$db->insertId();
		}
		
		/**
		 * 比较强大的多条语句查询方式, 但是解析的工作相对更多，所以简单的查询建议使用其他方式
		 * @param array $fields 需要的字段 exam: array("username", "password")
		 * @param array $option 刷选的条件,可以带$where方式，使用key=>array(">", "value")做符号刷选
		 * 	使用key=>value做等于号刷选
		 * @return Ambigous <NULL, multitype:multitype: >
		 */
		public function select(array $fields = null, array $option = null, $extra = null) {
			$option = $this->activeRecordCall($option);
			
			$sql = "SELECT ".$this->parseField($fields)." FROM $this->name". 
					(($option == null) ? "" : " WHERE ".$this->parseOption($option))." ".$extra;
			
			return self::$db->assocAll($sql);
		}
 			
		/**
		 * 获取数据库适配器 
		 * @return MysqlDb 使用的数据库适配器
		 */
 		public function adapter() {
 			return self::$db;
 		}
 		
 		public function __set($name, $value) {
 			$this->data[$name] =  $value;
 		}
 		
 		public function __get($name) {
 			return isset($this->data[$name]) ? $this->data[$name]:null;
 		}
 		
 		/**
 		 * 自动填充数据
 		 * @return boolean
 		 */
		public function create(array $data = null) { 
			if($this->name == "") {
				$this->error = "basemodel cannot use create function";
				return false;	
			}
			
			$this->data = (empty($data) ? $_POST : $data);	// 将POST数据当数据源
			
			if( $this->autoValidateRule != null) {			// 如果设定了规则则进行自动检验
				$length = count($this->autoValidateRule);
				for($i = 0; $i < $length; $i++) {
					if( !$this->autoValidate($this->autoValidateRule[$i]) ) {
						$this->data = array();
						$this->error = $this->autoValidateRule[$i][3];
						return false;
					}
				}
			}
			// 剔除表中没有的字段
			$this->autoFillData();
			_print($this->data);
			return true;
		} 	
		
		/**
		 * 对规则进行校验
		 * @param array $validateRule 单条规则格式array("字段名", "规则内容", "规则类型", "错误提示")
		 * @return boolean|mixed
		 */
		protected  function autoValidate(array $validateRule) {
			$type = $validateRule[2];
			$rule = $validateRule[1];
			$value = $this->data[$validateRule[0]];
			
			// 如果不是必须要且字段不存在则不判断
			if($type != self::VALIDATE_REQUIRE && $value == null) {
				return true;
			}
			
			switch($type) {
				case self::VALIDATE_IN:
				case self::VALIDATE_NOTIN:
					$range   = is_array($rule)? $rule : explode(',',$rule);
					return $type == self::VALIDATE_IN ? in_array($value ,$range) : !in_array($value ,$range);
				
				case self::VALIDATE_BEWTEEN:
				case self::VALIDATE_NOTBEWTEEN:
					if (is_array($rule)){
						$min    =    $rule[0];
						$max    =    $rule[1];
					}else{
						list($min,$max)   =  explode(',',$rule);
					}
					return $type == self::VALIDATE_BEWTEEN ? $value>=$min && $value<=$max : $value<$min || $value>$max;
				
				case self::VALIDATE_EQUAL:
				case self::VALIDATE_NOTEQUAL:
					return $type == self::VALIDATE_EQUAL ? $value == $rule : $value != $rule;
				
				case self::VALIDATE_LENGTH: // 验证长度
					$length  =  mb_strlen($value,'utf-8'); // 当前数据长度
					if(strpos($rule,',')) { // 长度区间
						list($min,$max)   =  explode(',',$rule);
						return $length >= $min && $length <= $max;
					}else{// 指定长度
						return $length == $rule;
					}
					
				case self::VALIDATE_REQUIRE:
					return !empty($value);
				
				case self::VALIDATE_EXPIRE:
					list($start,$end)   =  explode(',',$rule);
					if(!is_numeric($start)) $start   =  strtotime($start);
					if(!is_numeric($end)) $end   =  strtotime($end);
					return NOW_TIME >= $start && NOW_TIME <= $end;
					
				case self::VALIDATE_CONFRIM:
					return $value == $this->data[$rule];
					
				case self::VALIDATE_UNIQUE:
					$key = array_search($value, $this->data);
					return !$this->assoc("$key = '$value'");
				
				case self::VALIDATE_REGEX:
					return $this->regex($value,$rule);
					
				case self::VALIDATE_FUNCTION:
					return call_user_func($rule, $value);
			}	
		}
		
		protected function autoFillData() {
			$this->_checkTableInfo();
			foreach ($this->data as $item) {
				$keyname = array_keys($this->data, $item)[0];
				if( empty($this->fields[$keyname]) ) {
					unset($this->data[$keyname]);
				}
			}
		}
 		
 		/**
 		 * 查看是否使用ActiveRecord方式,如果是则将内部的data作为传入的data
 		 * @param unknown $data
 		 * @return Ambigous <unknown, multitype:>
 		 */
 		protected function activeRecordCall($data) {
 			$realdata = ( empty($data) && !empty($this->data) ) ? $this->data : $data;
 			$this->data = array();
 			return  $realdata;
 		}
 		
 		/**
 		 * 将field解析成  *(为空) 或者 field1, field2
 		 * @param unknown $fields
 		 */
 		protected function parseField($fields) {
 			if($fields == null)	return '*';
 			
 			$length = count($fields);
 			for($i = 0; $i < $length; $i++) {
 				if($i != 0) $fieldStr .= ", ";
 				$fieldStr .= $fields[$i];
 			}
 			return $fieldStr;
 		}
 		
 		/**
 		 * 如果$option的array中value是数组则认为是带符号的，
 		 * 将解析成 key1 SIGN value1 AND key2 SIGN value2
 		 * 否则是 key1 = value1 AND key2 = value2
 		 * @param unknown $option
 		 */
 		protected function parseOption($option) {
 			$i = 0;
 			foreach ($option as $sname=>$svalue) {
 				// 如果$option带有第三个选项 则拼接,否则默认为AND
 				if($i != 0)	$optionStr .= " AND ";
 				
 				if( is_array($svalue) ) {
 					$optionStr .= " ".$sname." ".$svalue[0]." '".self::$db->quoteInfo($svalue[1])."'";
 				} else {
 					$optionStr .= $sname." = '".self::$db->quoteInfo($svalue)."'";
 				}
 				$i++;
 			}
 			return $optionStr;
 		}
 		
 		/**
 		 * 将array解析成 "key1 = value1, key2 = value2"
 		 * @param unknown $data
 		 * @return string
 		 */
 		protected  function parseAssign($data) {
 			// 拼接条件刷选字段
 			$i = 0;
 			foreach ($data as $sname=>$svalue) {
 				if($i != 0)	$assignStr .= ",";
 		
 				$assignStr .= $sname." = '".self::$db->quoteInfo($svalue). "'";
 				$i++;
 			}
 			return $assignStr;
 		}
 		
 		protected function parseUpdateOption($data) {
 			$i = 0;
 			foreach ($data as $sname=>$svalue) {
 				if($i != 0)	$assignStr .= ", ";
 					
 				$assignStr .= $sname." = '".self::$db->quoteInfo($svalue). "'";
 				$i++;
 			}
 			return $assignStr;
 		}
 		
 		/**
 		 * 将array解析成两个 $keyValueStr = array(key=>"key1, key2", value=>"value1,value2")
 		 * @param unknown $data
 		 */
 		protected function parseKeyValue($data) {
 			$i = 0;
 			$keyValueStr = array();
 			foreach ($data as $sname=>$svalue) {
 				if($i != 0) {
 					$keyValueStr["key"] .= ", ";
 					$keyValueStr["value"].= ", ";
 				}
 				$keyValueStr["key"] .= $sname;
 				$keyValueStr["value"] .= "'".self::$db->quoteInfo($svalue)."'";
 				$i++;
 			}
 			return $keyValueStr;
 		}
 		
 		/**
 		 * 将$where条件解析成, key1 SIGN value1 AND key2 SIGN value2
 		 * @param unknown $where
 		 * @return string
 		 */
 		protected function parseWhere($where) {
 			if($where == null) {
 				$where = $this->parseOption($this->data);
 				$this->data = array();
 			}
 			return ($where != null) ? " WHERE $where" : '';
 		}
 		
 		protected function regex($rule, $value) {
 			$validate = array(
 					'require'   =>  '/.+/',
 					'email'     =>  '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
 					'url'       =>  '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
 					'currency'  =>  '/^\d+(\.\d+)?$/',
 					'number'    =>  '/^\d+$/',
 					'zip'       =>  '/^\d{6}$/',
 					'integer'   =>  '/^[-\+]?\d+$/',
 					'double'    =>  '/^[-\+]?\d+(\.\d+)?$/',
 					'english'   =>  '/^[A-Za-z]+$/',
 			);
 			// 检查是否有内置的正则表达式
 			if(isset($validate[strtolower($rule)]))
 				$rule = $validate[strtolower($rule)];
 			
 			return preg_match($rule,$value) === 1;
 		}
 		
 		public function _checkTableInfo() {
 			if(empty($this->fields)) {
 				$sql = "SHOW COLUMNS FROM  $this->name";
 				// $cid = self::$db->query($sql);
 				$data = self::$db->assocAll($sql);
 				$cnt = count($data);
 				for($i = 0; $i < $cnt; $i++){
 					$this->fields[$data[$i]["Field"]] = "1";
 				}
 			}
 			return $this->fields;

 		}
 		
 		public function lastSql() {
 			return self::$db->lastSql();
 		}
	} 